package cn.whb.hrm.service.impl;

import cn.whb.hrm.constant.CourseConstant;
import cn.whb.hrm.domain.CourseType;
import cn.whb.hrm.mapper.CourseTypeMapper;
import cn.whb.hrm.service.ICourseTypeService;
import cn.whb.hrm.util.AjaxResult;
import cn.whb.hrm.vo.CrumbsVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/*
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author whb
 * @since 2021-12-20
 **/

/**
 *  缓存穿透：缓存和数据库中都没有数据，并发量过大，所有请求全部访问数据库，数据库压力过大
 *  缓存击穿：缓存中没有数据，数据库中有数据，这时出现大量请求来访问这一条数据，全部交给数据库处理，压力过大
 *  缓存雪崩：大量缓存刚好同一时间过期，导致大量请求全部访问数据库，数据库压力太大了
 */

@Service
public class CourseTypeServiceImpl_redis extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {

    @Autowired
    private CourseTypeMapper typeMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    private ReentrantLock lock = new ReentrantLock();

    @Override
    public AjaxResult treeData() {
     /*//利用SQL嵌套查询
        List<CourseType> result = typeMapper.treeData();*/

        Object obj = redisTemplate.opsForValue().get(CourseConstant.COURSE_TYPE_DATA);
        List<CourseType> result = new ArrayList<>();
        if(obj!=null){
            System.out.println("从缓存中获取");
            result = (List<CourseType>)obj;
       }else {
            //加锁防止击穿
            if (lock.tryLock()){
                try {
                    result = getTreeData();
                    //缓存设置随机过期时间，防止缓存雪崩
                    int i = ThreadLocalRandom.current().nextInt(100, 200);//jdk6之后设置随机数
                    redisTemplate.opsForValue().set(CourseConstant.COURSE_TYPE_DATA,result,Long.valueOf(i), TimeUnit.MINUTES);
                    System.out.println("从数据库中获取");
                }finally {
                    lock.unlock();
                }
            }else {
                try {
                    //防止栈溢出
                    Thread.sleep(10L);
                    treeData();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return AjaxResult.me().setResultObj(result);
    }


    @Override
    public AjaxResult getCrumbs(Long typeId) {
        List<CrumbsVo> result = new ArrayList<>();
        //先查询到自己
        CourseType courseType = typeMapper.selectById(typeId);
        //获取到path，代表了自己的层级
        String path = courseType.getPath();
        String[] ids = path.split("\\.");
        //遍历整个层级的id
        for(String id:ids){
            Long tid = Long.valueOf(id);
            //得到own
            CourseType own = typeMapper.selectById(tid);
            Wrapper<CourseType> wrapper = new EntityWrapper<>();
            //得到自己的兄弟
            //select * from t_course_type where pid=own.pid and id <> own.id
            wrapper.eq("pid", own.getPid()).and().ne("id", own.getId());
            List<CourseType> bros = typeMapper.selectList(wrapper);
            //放到vo中
            CrumbsVo crumbsVo = new CrumbsVo(own, bros);
            //添加到result中
            result.add(crumbsVo);
        }
        return AjaxResult.me().setResultObj(result);
    }


    @Override
    public boolean insert(CourseType entity) {
        //删除缓存中的数据
        Boolean delete = redisTemplate.delete(CourseConstant.COURSE_TYPE_DATA);
        boolean b = super.insert(entity);
        if(delete){
            try {
                TimeUnit.MILLISECONDS.sleep(10L);
                delete = redisTemplate.delete(CourseConstant.COURSE_TYPE_DATA);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        if(!delete){
            //如果双删还是没有删除成功，就发一条消息到删除队列中，异步删除
            //如果异步删除也失败了，就直接联系管理员或者运维，操作中央缓存数据库删除
        }

        return b;
    }

    @Override
    public boolean deleteById(Serializable id) {
        //删除缓存中的数据
        redisTemplate.delete(CourseConstant.COURSE_TYPE_DATA);
        return super.deleteById(id);
    }

    @Override
    public boolean updateById(CourseType entity) {
        //删除缓存中的数据
        redisTemplate.delete(CourseConstant.COURSE_TYPE_DATA);
        return super.updateById(entity);
    }

    private List<CourseType> getTreeData() {
        List<CourseType> result = new ArrayList<>();
        //利用SQL查询到所有的courseType
        List<CourseType> list = typeMapper.selectList(null);
        Map<Long, CourseType> map = new HashMap<>();
        for(CourseType type:list){
            //建立每一个courseType和其id的关系
            map.put(type.getId(),type);
        }
        //遍历list
        for(CourseType type:list){
            //封装成嵌套的结构
            if(type.getPid()==0){//先找到第一层pid=0
                result.add(type);
            }else {
                Long pid = type.getPid();
                CourseType parent = map.get(pid);//找到他的父亲
                List<CourseType> children = parent.getChildren();
                children.add(type); //将自己放到父亲的children中
            }
        }
        return result;
    }
}
